#include "Server.h"
#include "NetworkMessenger.h"
#include "../EventSystem/EventSystem.h"

#include <string>
#include <fstream>
using std::fstream;
using std::string;

#ifdef _DEBUG
	#include "../Utility/Misc/DebugOutput.h"
#endif

Socket								Server::serverSocket;
vector<Server::MessageParserFunc>	Server::msgParser;
vector<ClientInfo>					Server::clients;
Timer								Server::timer;
NetworkHeader						Server::serverHeader;
unsigned int						Server::maxClients;
float								Server::msgRate;
float								Server::msgTimer;
bool								Server::isRunning;

void Server::Init()
{
	LoadServerSettings("Res/Data/Networking/serverData.txt");

	isRunning = true;
	clients.reserve(maxClients);
	msgParser.reserve(CL_MAX);
	msgParser.push_back(ParseConnectMessage);
	msgParser.push_back(ParseDisconnectMessage);
	msgParser.push_back(ParseBroadcastMessage);
	msgParser.push_back(ParsePlayerMoveMessage);

	InitializeSockets();
	serverSocket.OpenServer(NET_DEFAULT_PORT);
	
	timer.Init();
	msgTimer = 0.0f;
}

void Server::Update()
{
	timer.TimeStep();
	Address sender;
	NetworkMessage incomingMessage;

	int bytesRead = serverSocket.Receive(sender, incomingMessage.GetData(), incomingMessage.GetMaxBufferSize());
	incomingMessage.SetBufferSize(bytesRead);

	if(bytesRead)
	{
#ifdef _DEBUG
		std::ostringstream msg;
		msg << "Server Recieved <" << bytesRead << "> bytes from: " << (int)sender.GetA() << "." << (int)sender.GetB() << "." << (int)sender.GetC() << "." << (int)sender.GetD();
		DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, msg.str().c_str());
#endif

		if(MSG_UNRELIABLE == incomingMessage.ReadByte())
		{
			if(CheckSequence(incomingMessage, sender))
			{
				while(incomingMessage.GetReadCount() != incomingMessage.GetCurrentBufferSize())
				{
					(*msgParser[incomingMessage.ReadByte()])(incomingMessage, sender);
				}
			}
		}
	}

	msgTimer += timer.GetDeltaTimeFloat();

	if(msgTimer > SNAP_RATE(msgRate))
	{
		msgTimer = 0.0f;

		if(clients.size())
		{
			SendMessages();
		}
	}
}

bool Server::CheckSequence(NetworkMessage& _netMsg, Address& _sender)
{
	unsigned char sequence = _netMsg.ReadByte();
	int senderIndex = -1;
	for(unsigned int i = 0; i < clients.size(); ++i)
	{
		if(clients[i].clientAddr == _sender)
		{
			senderIndex = i;
			break;
		}
	}

#ifdef _DEBUG
	std::ostringstream msg;
	msg << "Sequence#:" << (unsigned int)sequence;
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, msg.str().c_str());
#endif

	if(senderIndex == -1)
	{
		return true;
	}

	if(IsSequenceMoreRecent(sequence, clients[senderIndex].header.sequenceNumber))
	{
		clients[senderIndex].header.sequenceNumber = sequence;
		return true;
	}

	return false;
}

void Server::SendMessages()
{
	for(unsigned int i = 0; i < clients.size(); ++i)
	{
		if(clients[i].msg.GetCurrentBufferSize() > sizeof(NetworkHeader))
		{
			serverSocket.Send(clients[i].clientAddr, clients[i].msg.GetData(), clients[i].msg.GetCurrentBufferSize());

			clients[i].msg.Clear();
			WriteMessageHeader(clients[i].msg, clients[i].header);
		}
	}
}

void Server::LoadServerSettings(const char* const _filePath)
{
	char line[256];

	fstream in(_filePath, std::ios_base::in);

	if(in.is_open())
	{
		while( in.getline(line,256) )
		{
			std::istringstream newLine(line, std::istringstream::in);

			string command;

			newLine >> command;

			if(command == "MaxClients")
			{				
				newLine >> maxClients;
			}
			else if(command == "MessageRate")
			{
				newLine >> msgRate;
			}
		}
	}

	in.close();

#ifdef _DEBUG
		std::ostringstream msg;
		msg << "Init server settings\nMax Clients: " << maxClients << "\nMessage Rate: " << msgRate;
		DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, msg.str().c_str());
#endif

}

void Server::Shutdown()
{
	ShutdownSockets();
}

void Server::ParseBroadcastMessage(NetworkMessage& _netMsg, Address& _incomingAddress)
{
#ifdef _DEBUG
	std::ostringstream msg;
	msg << "Recieved broadcast from: " << (int)_incomingAddress.GetA() << "." << (int)_incomingAddress.GetB() << "." 
		<< (int)_incomingAddress.GetC() << "." << (int)_incomingAddress.GetD() << ":" << _incomingAddress.GetPort();
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, msg.str().c_str());
#endif
	NetworkMessage message;

	if(clients.size() < maxClients)
	{
		ClientInfo newClient(_incomingAddress);
		clients.push_back(newClient);
		WriteMessageHeader(clients[clients.size()-1].msg, serverHeader);
		ServerMessenger::Connect(clients[clients.size()-1].msg);
		serverSocket.Send(_incomingAddress, clients[clients.size()-1].msg.GetData(), clients[clients.size()-1].msg.GetCurrentBufferSize());
		clients[clients.size()-1].msg.Clear();
	}
	else
	{
		ServerMessenger::Full(message);
		serverSocket.Send(_incomingAddress, message.GetData(), message.GetCurrentBufferSize());
	}
}

void Server::ParseConnectMessage(NetworkMessage& _netMsg, Address& _incomingAddress)
{
#ifdef _DEBUG
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, "Function pointer worked!");
#endif
}

void Server::ParseDisconnectMessage(NetworkMessage& _netMsg, Address& _incomingAddress)
{
#ifdef _DEBUG
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, "Function pointer worked!");
#endif
}

static PlayerMoveEvent pmEvent;
void Server::ParsePlayerMoveMessage(NetworkMessage& _netMsg, Address& _incomingAddress)
{
#ifdef _DEBUG
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, "Recieved player move message from client");
#endif

	NetworkMessage moveMessage;
	moveMessage.WriteByte(SV_PLAYER_MOVE);

	pmEvent = *((PlayerMoveEvent*)_netMsg.ReadData(sizeof(PlayerMoveEvent)));

#ifdef _DEBUG
	std::ostringstream msg;
	msg << "Input: " << (int)pmEvent.direction;
	DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING, msg.str().c_str());
#endif

	EventSystem::SendEvent(PLAYER_MOVE_SV, &pmEvent);
}
